<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  
  <title>Mina系列三之IoFilter | Hexo</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta name="description" content="简介　　IoFilter 是 MINA 的核心结构之一，它过滤 IoService 和 IoHandler 之间的所有 I/O 事件和请求，最后将数据交由IoHandler进行处理。这里可以看到Mina的一个设计理念就是业务代码和数据包处理代码分离，业务代码只专注于业务逻辑，其他的逻辑如：数据包的解析，封装，过滤等则交由IoFilterChain来处理。IoFilterChain可以看成是Mina">
<meta property="og:type" content="article">
<meta property="og:title" content="Mina系列三之IoFilter">
<meta property="og:url" content="http://yoursite.com/2016/01/18/nio/17.Mina系列三之IoFilter/index.html">
<meta property="og:site_name" content="Hexo">
<meta property="og:description" content="简介　　IoFilter 是 MINA 的核心结构之一，它过滤 IoService 和 IoHandler 之间的所有 I/O 事件和请求，最后将数据交由IoHandler进行处理。这里可以看到Mina的一个设计理念就是业务代码和数据包处理代码分离，业务代码只专注于业务逻辑，其他的逻辑如：数据包的解析，封装，过滤等则交由IoFilterChain来处理。IoFilterChain可以看成是Mina">
<meta property="og:image" content="http://yoursite.com/images/mina-filter-order.png">
<meta property="og:updated_time" content="2016-01-29T18:16:55.000Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Mina系列三之IoFilter">
<meta name="twitter:description" content="简介　　IoFilter 是 MINA 的核心结构之一，它过滤 IoService 和 IoHandler 之间的所有 I/O 事件和请求，最后将数据交由IoHandler进行处理。这里可以看到Mina的一个设计理念就是业务代码和数据包处理代码分离，业务代码只专注于业务逻辑，其他的逻辑如：数据包的解析，封装，过滤等则交由IoFilterChain来处理。IoFilterChain可以看成是Mina">
  
    <link rel="alternative" href="/atom.xml" title="Hexo" type="application/atom+xml">
  
  
    <link rel="icon" href="/favicon.png">
  
  <link href="//fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet" type="text/css">
  <link rel="stylesheet" href="/css/style.css" type="text/css">
  

</head>
<body>
  <div id="container">
    <div id="wrap">
      <header id="header">
  <div id="banner"></div>
  <div id="header-outer" class="outer">
    <div id="header-title" class="inner">
      <h1 id="logo-wrap">
        <a href="/" id="logo">Hexo</a>
      </h1>
      
    </div>
    <div id="header-inner" class="inner">
      <nav id="main-nav">
        <a id="main-nav-toggle" class="nav-icon"></a>
        
          <a class="main-nav-link" href="/">Home</a>
        
          <a class="main-nav-link" href="/archives">Archives</a>
        
      </nav>
      <nav id="sub-nav">
        
          <a id="nav-rss-link" class="nav-icon" href="/atom.xml" title="RSS Feed"></a>
        
        <a id="nav-search-btn" class="nav-icon" title="Search"></a>
      </nav>
      <div id="search-form-wrap">
        <form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" results="0" class="search-form-input" placeholder="Search"><button type="submit" class="search-form-submit">&#xF002;</button><input type="hidden" name="sitesearch" value="http://yoursite.com"></form>
      </div>
    </div>
  </div>
</header>
      <div class="outer">
        <section id="main"><article id="post-nio/17.Mina系列三之IoFilter" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2016/01/18/nio/17.Mina系列三之IoFilter/" class="article-date">
  <time datetime="2016-01-18T06:23:00.000Z" itemprop="datePublished">2016-01-18</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/nio/">nio</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 class="article-title" itemprop="name">
      Mina系列三之IoFilter
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="u7B80_u4ECB"><a href="#u7B80_u4ECB" class="headerlink" title="简介"></a>简介</h2><p>　　IoFilter 是 MINA 的核心结构之一，它过滤 IoService 和 IoHandler 之间的所有 I/O 事件和请求，最后将数据交由IoHandler进行处理。这里可以看到Mina的一个设计理念就是<strong>业务代码和数据包处理代码分离</strong>，业务代码只专注于业务逻辑，其他的逻辑如：数据包的解析，封装，过滤等则交由IoFilterChain来处理。IoFilterChain可以看成是Mina处理流程的扩展点。这样的划分使得结构更加清晰，代码分工更明确。开发者通过往Chain中添加IoFilter，来增强处理流程，而不会影响后面的业务逻辑代码。<br>　　这里先直接列出分析的结果，想看源码的朋友可以继续浏览文章！<br>　　1. 过滤器链涉及到的类包括：IoFilterChainBuilder、IoFilterChain、IoFilter、NextFilter和Entry等<br>　　2. Mina在初始化时，通过一个List维护添加进去的链表<br>　　3. 每次有新的客户端连接时，调用IoFilterChainBuilder的buildFilterChain方法，为每个新连接的IoSession构建一个过滤器链IoFilterChain（IoSession在new的同时new一个IoFilterChain）<br>　　4. IoFilterChain内部维护了一个head和tail的Filter，业务代码添加的Filter都放在这两个之间，通过NextFilter相应的方法回调IoFilterChain相应的方法（比如callNextMessageReceived），这样就形成了过滤器链的调用过程<br>　　5. IoFilterChain的内部类TailFilter(过滤器链)最后执行，负责调用业务层的IoHander<br>　　6. 每个过滤器连的上下过滤器、名称等信息，都封装成一个Entry，形成一个过滤器链上的一个节点<br>　　7. Filter执行顺序为：服务端处理连接、数据读取为：head =&gt; tail =&gt; handelr，服务端写入数据为：tail =&gt; head。所以HeadFilter实现了filterWrite方法，TailFilter实现了messageReceived、sessionCreate等方法。该顺序请参考下图：<img src="/images/mina-filter-order.png" alt="IoFilter执行顺序图"><br>　　mina已经内置实现了很多过滤器，如黑名单、压缩和编解码等，如下表所示！</p>
<table>
<thead>
<tr>
<th style="text-align:left">过滤器</th>
<th style="text-align:left">类</th>
<th style="text-align:left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">黑名单</td>
<td style="text-align:left">BlacklistFilter</td>
<td style="text-align:left">阻止列入黑名单的远程地址的连接</td>
</tr>
<tr>
<td style="text-align:left">缓冲写</td>
<td style="text-align:left">BufferedWriteFilter</td>
<td style="text-align:left">发送缓存过滤器，缓存发送的消息，避免短小消息频繁发送</td>
</tr>
<tr>
<td style="text-align:left">协议编解码器</td>
<td style="text-align:left">ProtocolCodecFilter</td>
<td style="text-align:left">编解码过滤器，最常用之二</td>
</tr>
<tr>
<td style="text-align:left">压缩</td>
<td style="text-align:left">CompressionFilter</td>
<td style="text-align:left">数据压缩过滤器</td>
</tr>
<tr>
<td style="text-align:left">连接控制</td>
<td style="text-align:left">ConnectionThrottleFilter</td>
<td style="text-align:left">连接控制过滤器，对同一IP地址频繁的创建连接的时间间隔进行控制</td>
</tr>
<tr>
<td style="text-align:left">错误生成</td>
<td style="text-align:left">ErrorGeneratingFilter</td>
<td style="text-align:left"></td>
</tr>
<tr>
<td style="text-align:left">执行者</td>
<td style="text-align:left">ExecutorFilter</td>
<td style="text-align:left">处理线程池过滤器，让每个请求或者事件都通过线程池去执行</td>
</tr>
<tr>
<td style="text-align:left">FileRegion 转换</td>
<td style="text-align:left">FileRegionWriteFilter</td>
<td style="text-align:left">文件转换过滤器，通常应该由IoProcess做这件事，<br>但若需要压缩或者修改时，可通过过滤器链之间的配合来实现</td>
</tr>
<tr>
<td style="text-align:left">保持动态</td>
<td style="text-align:left">KeepAliveFilter</td>
<td style="text-align:left">心跳包过滤器，在idle状态时发送心跳包，并能对超时进行处理</td>
</tr>
<tr>
<td style="text-align:left">日志</td>
<td style="text-align:left">LoggingFilter</td>
<td style="text-align:left">日志记录过滤器，最常用之一</td>
</tr>
<tr>
<td style="text-align:left">MDC 注入</td>
<td style="text-align:left">MdcInjectionFilter</td>
<td style="text-align:left">日志信息注入过滤器，MDC(Mapped Diagnostic Context有译作线程映射表)是日志框架维护的一组信息键值对，<br>可向日志输出信息中插入一些想要显示的内容。</td>
</tr>
<tr>
<td style="text-align:left">等待</td>
<td style="text-align:left">NoopFilter</td>
<td style="text-align:left">用作内部测试的filter，什么也没做</td>
</tr>
<tr>
<td style="text-align:left">分析器</td>
<td style="text-align:left">ProfilerTimerFilter</td>
<td style="text-align:left">时间分析过滤器，记录各种事件消耗的时间</td>
</tr>
<tr>
<td style="text-align:left">代理</td>
<td style="text-align:left">ProxyFilter</td>
<td style="text-align:left">是IoConnector在连接握手时自动加入的过滤器，握手成功后就透明了</td>
</tr>
<tr>
<td style="text-align:left">引用计数</td>
<td style="text-align:left">ReferenceCountingFilter</td>
<td style="text-align:left">引用数过滤器，能记录该过滤器被加入或移除过滤器链的次数，真实使用</td>
</tr>
</tbody>
</table>
<p>时继承它。|<br>|请求响应|RequestResponseFilter|继承WriteRequest|<br>|会话属性初始化|SessionAttributeInitializingFilter|初始化过滤器|<br>|写流|StreamWriteFilter|InputStream直接转换成IoBuffer的过滤器|<br>|SSL过滤器|SslFilter|TCP/IP层面的SSl加解密过滤器|<br>|写请求|WriteRequestFilter|简化IoFilter IoEventType.WRITE事件的实现的抽象过滤器|</p>
<h2 id="IoFilterChainBuilder"><a href="#IoFilterChainBuilder" class="headerlink" title="IoFilterChainBuilder"></a>IoFilterChainBuilder</h2><p>　　在上一篇的示例代码中，我们调用了AbstractIoService的getFilterChain的方法，该方法返回了DefaultIoFilterChainBuilder的一个实例。顾名思义，它是一个IoFilterChain的构造者。下面我们看看它的声明和默认的实现类DefaultIoFilterChainBuilder，这里只贴出了重要的代码。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">IoFilterChainBuilder</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">buildFilterChain</span><span class="params">(IoFilterChain chain)</span> <span class="keyword">throws</span> Exception</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DefaultIoFilterChainBuilder</span> <span class="keyword">implements</span> <span class="title">IoFilterChainBuilder</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> List&lt;Entry&gt; entries;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">DefaultIoFilterChainBuilder</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        entries = <span class="keyword">new</span> CopyOnWriteArrayList&lt;Entry&gt;();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">addLast</span><span class="params">(String name, IoFilter filter)</span> </span>&#123;</span><br><span class="line">        register(entries.size(), <span class="keyword">new</span> EntryImpl(name, filter));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">buildFilterChain</span><span class="params">(IoFilterChain chain)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        <span class="keyword">for</span> (Entry e : entries) &#123;</span><br><span class="line">            chain.addLast(e.getName(), e.getFilter());</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">register</span><span class="params">(<span class="keyword">int</span> index, Entry e)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (contains(e.getName())) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">"Other filter is using the same name: "</span> + e.getName());</span><br><span class="line">        &#125;</span><br><span class="line">        entries.add(index, e);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="class"><span class="keyword">class</span> <span class="title">EntryImpl</span> <span class="keyword">implements</span> <span class="title">Entry</span> </span>&#123;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> String name;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">volatile</span> IoFilter filter;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">private</span> <span class="title">EntryImpl</span><span class="params">(String name, IoFilter filter)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.name = name;</span><br><span class="line">            <span class="keyword">this</span>.filter = filter;</span><br><span class="line">        &#125;</span><br><span class="line">		</span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">addAfter</span><span class="params">(String name, IoFilter filter)</span> </span>&#123;</span><br><span class="line">            DefaultIoFilterChainBuilder.<span class="keyword">this</span>.addAfter(getName(), name, filter);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">addBefore</span><span class="params">(String name, IoFilter filter)</span> </span>&#123;</span><br><span class="line">            DefaultIoFilterChainBuilder.<span class="keyword">this</span>.addBefore(getName(), name, filter);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">remove</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            DefaultIoFilterChainBuilder.<span class="keyword">this</span>.remove(getName());</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">replace</span><span class="params">(IoFilter newFilter)</span> </span>&#123;</span><br><span class="line">            DefaultIoFilterChainBuilder.<span class="keyword">this</span>.replace(getName(), newFilter);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　可以看到DefaultIoFilterChainBuilder最重要的方法就是 buildFilterChain ，最重要的一个成员变量就是entries。在Mina初始化时，我们添加了多个IoFilter的实例到entries中。<strong>每次有新的客户端连接时，都会创建一个新的IoSession实例（在其构造函数中初始化一个DefaultIoFilterChain），并调用 buildFilterChain 方法，为新的IoSession的过滤器链初始化</strong>！buildFilterChain 方法内部循环调用了DefaultIoFilterChain的addLast方法，实现了过滤器链的前后链接过程！</p>
<h2 id="DefaultIoFilterChain"><a href="#DefaultIoFilterChain" class="headerlink" title="DefaultIoFilterChain"></a>DefaultIoFilterChain</h2><p>　　我们看看它提供了哪些方法。注意，其内部声明了一个非常重要的Entry接口类，用于记录当前Filter和其下一个Filter<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">IoFilterChain</span> </span>&#123;</span><br><span class="line">    <span class="function">IoSession <span class="title">getSession</span><span class="params">()</span></span>;</span><br><span class="line">    <span class="function">Entry <span class="title">getEntry</span><span class="params">(String name)</span></span>;</span><br><span class="line">    <span class="comment">//省略其他重载方法</span></span><br><span class="line">    <span class="function">IoFilter <span class="title">get</span><span class="params">(String name)</span></span>;</span><br><span class="line">    <span class="comment">//省略其他重载方法</span></span><br><span class="line">    <span class="function">NextFilter <span class="title">getNextFilter</span><span class="params">(Class&lt;? extends IoFilter&gt; filterType)</span></span>;</span><br><span class="line">    <span class="function">List&lt;Entry&gt; <span class="title">getAll</span><span class="params">()</span></span>;</span><br><span class="line">    <span class="function">List&lt;Entry&gt; <span class="title">getAllReversed</span><span class="params">()</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">boolean</span> <span class="title">contains</span><span class="params">(String name)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">addLast</span><span class="params">(String name, IoFilter filter)</span></span>;</span><br><span class="line">    <span class="function">IoFilter <span class="title">replace</span><span class="params">(String name, IoFilter newFilter)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">replace</span><span class="params">(IoFilter oldFilter, IoFilter newFilter)</span></span>;</span><br><span class="line">    <span class="function">IoFilter <span class="title">remove</span><span class="params">(String name)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">remove</span><span class="params">(IoFilter filter)</span></span>;</span><br><span class="line">    <span class="function">IoFilter <span class="title">remove</span><span class="params">(Class&lt;? extends IoFilter&gt; filterType)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">clear</span><span class="params">()</span> <span class="keyword">throws</span> Exception</span>;</span><br><span class="line">    <span class="comment">//省略fireSessionCreated、fireSessionIdle等方法</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">fireMessageReceived</span><span class="params">(Object message)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">fireInputClosed</span><span class="params">()</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">fireFilterWrite</span><span class="params">(WriteRequest writeRequest)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">fireFilterClose</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//维护一个name-filter对的过滤器</span></span><br><span class="line">    <span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Entry</span> </span>&#123;</span><br><span class="line">        <span class="function">String <span class="title">getName</span><span class="params">()</span></span>;</span><br><span class="line">        <span class="function">IoFilter <span class="title">getFilter</span><span class="params">()</span></span>;</span><br><span class="line">        <span class="function">NextFilter <span class="title">getNextFilter</span><span class="params">()</span></span>;</span><br><span class="line">        <span class="function"><span class="keyword">void</span> <span class="title">addBefore</span><span class="params">(String name, IoFilter filter)</span></span>;</span><br><span class="line">        <span class="function"><span class="keyword">void</span> <span class="title">addAfter</span><span class="params">(String name, IoFilter filter)</span></span>;</span><br><span class="line">        <span class="function"><span class="keyword">void</span> <span class="title">replace</span><span class="params">(IoFilter newFilter)</span></span>;</span><br><span class="line">        <span class="function"><span class="keyword">void</span> <span class="title">remove</span><span class="params">()</span></span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DefaultIoFilterChain</span> <span class="keyword">implements</span> <span class="title">IoFilterChain</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> AbstractIoSession session;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Map&lt;String, Entry&gt; name2entry = <span class="keyword">new</span> ConcurrentHashMap&lt;String, Entry&gt;();</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> EntryImpl head;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> EntryImpl tail;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">DefaultIoFilterChain</span><span class="params">(AbstractIoSession session)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.session = session;</span><br><span class="line">        head = <span class="keyword">new</span> EntryImpl(<span class="keyword">null</span>, <span class="keyword">null</span>, <span class="string">"head"</span>, <span class="keyword">new</span> HeadFilter());</span><br><span class="line">        tail = <span class="keyword">new</span> EntryImpl(head, <span class="keyword">null</span>, <span class="string">"tail"</span>, <span class="keyword">new</span> TailFilter());</span><br><span class="line">        head.nextEntry = tail;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//addFirst、addBefore和addAfter等方法</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">addLast</span><span class="params">(String name, IoFilter filter)</span> </span>&#123;</span><br><span class="line">        checkAddable(name);</span><br><span class="line">        register(tail.prevEntry, name, filter);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> IoFilter <span class="title">remove</span><span class="params">(String name)</span> </span>&#123;</span><br><span class="line">        EntryImpl entry = checkOldName(name);</span><br><span class="line">        deregister(entry);</span><br><span class="line">        <span class="keyword">return</span> entry.getFilter();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">clear</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        List&lt;IoFilterChain.Entry&gt; l = <span class="keyword">new</span> ArrayList&lt;IoFilterChain.Entry&gt;(name2entry.values());</span><br><span class="line">        <span class="keyword">for</span> (IoFilterChain.Entry entry : l) &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                deregister((EntryImpl) entry);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> IoFilterLifeCycleException(<span class="string">"clear(): "</span> + entry.getName() + <span class="string">" in "</span> + getSession(), e);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">register</span><span class="params">(EntryImpl prevEntry, String name, IoFilter filter)</span> </span>&#123;</span><br><span class="line">        EntryImpl newEntry = <span class="keyword">new</span> EntryImpl(prevEntry, prevEntry.nextEntry, name, filter);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            filter.onPreAdd(<span class="keyword">this</span>, name, newEntry.getNextFilter());</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> IoFilterLifeCycleException(<span class="string">"onPreAdd(): "</span> + name + <span class="string">':'</span> + filter + <span class="string">" in "</span> + getSession(), e);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        prevEntry.nextEntry.prevEntry = newEntry;</span><br><span class="line">        prevEntry.nextEntry = newEntry;</span><br><span class="line">        name2entry.put(name, newEntry);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            filter.onPostAdd(<span class="keyword">this</span>, name, newEntry.getNextFilter());</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            deregister0(newEntry);</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> IoFilterLifeCycleException(<span class="string">"onPostAdd(): "</span> + name + <span class="string">':'</span> + filter + <span class="string">" in "</span> + getSession(), e);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">deregister</span><span class="params">(EntryImpl entry)</span> </span>&#123;</span><br><span class="line">        IoFilter filter = entry.getFilter();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            filter.onPreRemove(<span class="keyword">this</span>, entry.getName(), entry.getNextFilter());</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> IoFilterLifeCycleException(<span class="string">"onPreRemove(): "</span> + entry.getName() + <span class="string">':'</span> + filter + <span class="string">" in "</span></span><br><span class="line">                    + getSession(), e);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        deregister0(entry);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            filter.onPostRemove(<span class="keyword">this</span>, entry.getName(), entry.getNextFilter());</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> IoFilterLifeCycleException(<span class="string">"onPostRemove(): "</span> + entry.getName() + <span class="string">':'</span> + filter + <span class="string">" in "</span></span><br><span class="line">                    + getSession(), e);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">deregister0</span><span class="params">(EntryImpl entry)</span> </span>&#123;</span><br><span class="line">        EntryImpl prevEntry = entry.prevEntry;</span><br><span class="line">        EntryImpl nextEntry = entry.nextEntry;</span><br><span class="line">        prevEntry.nextEntry = nextEntry;</span><br><span class="line">        nextEntry.prevEntry = prevEntry;</span><br><span class="line"></span><br><span class="line">        name2entry.remove(entry.name);</span><br><span class="line">    &#125;</span><br><span class="line">	</span><br><span class="line">	<span class="comment">//省略其他的一些fireSessionCreated、callNextSessionCreated等方法</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">fireMessageReceived</span><span class="params">(Object message)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (message <span class="keyword">instanceof</span> IoBuffer) &#123;</span><br><span class="line">            session.increaseReadBytes(((IoBuffer) message).remaining(), System.currentTimeMillis());</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        callNextMessageReceived(head, session, message);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//调用下一个filter</span></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">callNextMessageReceived</span><span class="params">(Entry entry, IoSession session, Object message)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            IoFilter filter = entry.getFilter();</span><br><span class="line">            NextFilter nextFilter = entry.getNextFilter();</span><br><span class="line">            filter.messageReceived(nextFilter, session, message);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            fireExceptionCaught(e);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Error e) &#123;</span><br><span class="line">            fireExceptionCaught(e);</span><br><span class="line">            <span class="keyword">throw</span> e;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="class"><span class="keyword">class</span> <span class="title">HeadFilter</span> <span class="keyword">extends</span> <span class="title">IoFilterAdapter</span> </span>&#123;</span><br><span class="line">        <span class="annotation">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">filterWrite</span><span class="params">(NextFilter nextFilter, IoSession session, WriteRequest writeRequest)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line"></span><br><span class="line">            AbstractIoSession s = (AbstractIoSession) session;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// Maintain counters.</span></span><br><span class="line">            <span class="keyword">if</span> (writeRequest.getMessage() <span class="keyword">instanceof</span> IoBuffer) &#123;</span><br><span class="line">                IoBuffer buffer = (IoBuffer) writeRequest.getMessage();</span><br><span class="line">                <span class="comment">// I/O processor implementation will call buffer.reset()</span></span><br><span class="line">                <span class="comment">// it after the write operation is finished, because</span></span><br><span class="line">                <span class="comment">// the buffer will be specified with messageSent event.</span></span><br><span class="line">                buffer.mark();</span><br><span class="line">                <span class="keyword">int</span> remaining = buffer.remaining();</span><br><span class="line"></span><br><span class="line">                <span class="keyword">if</span> (remaining &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                    s.increaseScheduledWriteBytes(remaining);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                s.increaseScheduledWriteMessages();</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            WriteRequestQueue writeRequestQueue = s.getWriteRequestQueue();</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (!s.isWriteSuspended()) &#123;</span><br><span class="line">                <span class="keyword">if</span> (writeRequestQueue.isEmpty(session)) &#123;</span><br><span class="line">                    <span class="comment">// We can write directly the message</span></span><br><span class="line">                    s.getProcessor().write(s, writeRequest);</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    s.getWriteRequestQueue().offer(s, writeRequest);</span><br><span class="line">                    s.getProcessor().flush(s);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                s.getWriteRequestQueue().offer(s, writeRequest);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="annotation">@SuppressWarnings</span>(<span class="string">"unchecked"</span>)</span><br><span class="line">        <span class="annotation">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">filterClose</span><span class="params">(NextFilter nextFilter, IoSession session)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">            ((AbstractIoSession) session).getProcessor().remove(session);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">TailFilter</span> <span class="keyword">extends</span> <span class="title">IoFilterAdapter</span> </span>&#123;</span><br><span class="line">        <span class="comment">//省略sessionCreated、messageSent等方法</span></span><br><span class="line">        <span class="annotation">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">messageReceived</span><span class="params">(NextFilter nextFilter, IoSession session, Object message)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">            AbstractIoSession s = (AbstractIoSession) session;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (!(message <span class="keyword">instanceof</span> IoBuffer)) &#123;</span><br><span class="line">                s.increaseReadMessages(System.currentTimeMillis());</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (!((IoBuffer) message).hasRemaining()) &#123;</span><br><span class="line">                s.increaseReadMessages(System.currentTimeMillis());</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// Update the statistics</span></span><br><span class="line">            <span class="keyword">if</span> (session.getService() <span class="keyword">instanceof</span> AbstractIoService) &#123;</span><br><span class="line">                ((AbstractIoService) session.getService()).getStatistics().updateThroughput(System.currentTimeMillis());</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// Propagate the message</span></span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                session.getHandler().messageReceived(s, message);</span><br><span class="line">            &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">                <span class="keyword">if</span> (s.getConfig().isUseReadOperation()) &#123;</span><br><span class="line">                    s.offerReadFuture(message);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="class"><span class="keyword">class</span> <span class="title">EntryImpl</span> <span class="keyword">implements</span> <span class="title">Entry</span> </span>&#123;</span><br><span class="line">        <span class="keyword">private</span> EntryImpl prevEntry;</span><br><span class="line">        <span class="keyword">private</span> EntryImpl nextEntry;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> String name;</span><br><span class="line">        <span class="keyword">private</span> IoFilter filter;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> NextFilter nextFilter;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">private</span> <span class="title">EntryImpl</span><span class="params">(EntryImpl prevEntry, EntryImpl nextEntry, String name, IoFilter filter)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">this</span>.prevEntry = prevEntry;</span><br><span class="line">            <span class="keyword">this</span>.nextEntry = nextEntry;</span><br><span class="line">            <span class="keyword">this</span>.name = name;</span><br><span class="line">            <span class="keyword">this</span>.filter = filter;</span><br><span class="line">            <span class="keyword">this</span>.nextFilter = <span class="keyword">new</span> NextFilter() &#123;</span><br><span class="line">                <span class="comment">////其他的一些方法，比如sessionOpened、sessionIdle等省略</span></span><br><span class="line">                <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">messageReceived</span><span class="params">(IoSession session, Object message)</span> </span>&#123;</span><br><span class="line">                    Entry nextEntry = EntryImpl.<span class="keyword">this</span>.nextEntry;</span><br><span class="line">                    callNextMessageReceived(nextEntry, session, message);</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">filterWrite</span><span class="params">(IoSession session, WriteRequest writeRequest)</span> </span>&#123;</span><br><span class="line">                    Entry nextEntry = EntryImpl.<span class="keyword">this</span>.prevEntry;</span><br><span class="line">                    callPreviousFilterWrite(nextEntry, session, writeRequest);</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">filterClose</span><span class="params">(IoSession session)</span> </span>&#123;</span><br><span class="line">                    Entry nextEntry = EntryImpl.<span class="keyword">this</span>.prevEntry;</span><br><span class="line">                    callPreviousFilterClose(nextEntry, session);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　DefaultIoFilterChain内部维护了过滤器链的首尾两个节点：head和tail，均为EntryImpl的实例。每个EntryImpl都存在上一个节点和下一个节点，这样就形成了一个链表关系。对下一个节点的sessionCreated、sessionIdle等方法的调用都是通过匿名类NextFilter提供的方法调用的。<br>　　其内部维护的IoFilterAdapter类型的tail作为过滤器链的最后一个环节，负责调用IoHander相应的方法！下面看看接口IoFilter及其内部接口NextFilter。</p>
<h2 id="IoFilter"><a href="#IoFilter" class="headerlink" title="IoFilter"></a>IoFilter</h2><p>　　IoFilter作为所有过滤器的基础接口，提供了过滤器从初始化、数据读写和销毁的通用方法。需要特别说明的是其声明了一个内部接口NextFilter，用于维护过滤器链的前后级调用过程！虽然有IoFilter和NextFilter两个接口，接口方法都差不多，但最后真正业务的执行者还是IoFilter的实现，IoFilterAdapter做为它的默认实现，完成了适配器的功能，以后的类可以直接继承它而不用实现IoFilter接口，想实现哪个方法只需要覆盖IoFilterAdapter的类的方法即可。NextFilter只起到转发的作用，如消息接收处理方法（messageReceived）：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">IoFilter</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">init</span><span class="params">()</span> <span class="keyword">throws</span> Exception</span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">destroy</span><span class="params">()</span> <span class="keyword">throws</span> Exception</span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">onPreAdd</span><span class="params">(IoFilterChain parent, String name, NextFilter nextFilter)</span> <span class="keyword">throws</span> Exception</span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">onPostAdd</span><span class="params">(IoFilterChain parent, String name, NextFilter nextFilter)</span> <span class="keyword">throws</span> Exception</span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">onPreRemove</span><span class="params">(IoFilterChain parent, String name, NextFilter nextFilter)</span> <span class="keyword">throws</span> Exception</span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">onPostRemove</span><span class="params">(IoFilterChain parent, String name, NextFilter nextFilter)</span> <span class="keyword">throws</span> Exception</span>;</span><br><span class="line">    <span class="comment">//省略sessionCreated、sessionIdle等方法</span></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">messageReceived</span><span class="params">(NextFilter nextFilter, IoSession session, Object message)</span> <span class="keyword">throws</span> Exception</span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">filterClose</span><span class="params">(NextFilter nextFilter, IoSession session)</span> <span class="keyword">throws</span> Exception</span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">filterWrite</span><span class="params">(NextFilter nextFilter, IoSession session, WriteRequest writeRequest)</span> <span class="keyword">throws</span> Exception</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">NextFilter</span> </span>&#123;</span><br><span class="line">        <span class="comment">//省略sessionCreated、sessionIdle等方法</span></span><br><span class="line">        <span class="function"><span class="keyword">void</span> <span class="title">inputClosed</span><span class="params">(IoSession session)</span></span>;</span><br><span class="line">        <span class="function"><span class="keyword">void</span> <span class="title">messageReceived</span><span class="params">(IoSession session, Object message)</span></span>;</span><br><span class="line">        <span class="function"><span class="keyword">void</span> <span class="title">filterWrite</span><span class="params">(IoSession session, WriteRequest writeRequest)</span></span>;</span><br><span class="line">        <span class="function"><span class="keyword">void</span> <span class="title">filterClose</span><span class="params">(IoSession session)</span></span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">IoFilterAdapter</span> <span class="keyword">implements</span> <span class="title">IoFilter</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">init</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>&#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">destroy</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>&#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onPreAdd</span><span class="params">(IoFilterChain parent, String name, NextFilter nextFilter)</span> <span class="keyword">throws</span> Exception </span>&#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onPostAdd</span><span class="params">(IoFilterChain parent, String name, NextFilter nextFilter)</span> <span class="keyword">throws</span> Exception </span>&#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onPreRemove</span><span class="params">(IoFilterChain parent, String name, NextFilter nextFilter)</span> <span class="keyword">throws</span> Exception </span>&#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onPostRemove</span><span class="params">(IoFilterChain parent, String name, NextFilter nextFilter)</span> <span class="keyword">throws</span> Exception </span>&#123;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//sessionOpened等方法类型</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">messageReceived</span><span class="params">(NextFilter nextFilter, IoSession session, Object message)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        nextFilter.messageReceived(session, message);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h2 id="u81EA_u5B9A_u4E49_u8FC7_u6EE4_u5668"><a href="#u81EA_u5B9A_u4E49_u8FC7_u6EE4_u5668" class="headerlink" title="自定义过滤器"></a>自定义过滤器</h2><p>　　下面我们实现两个过滤器：MyFilter1和MyFilter2，运行后两个过滤器的sessionCreated方法都执行了，因为MyFilter1的sessionCreated方法调用了父类IoFilterAdapter的方法，父类方法又执行了nextFilter.sessionCreated(session, message);。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyFilter1</span> <span class="keyword">extends</span> <span class="title">IoFilterAdapter</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">sessionCreated</span><span class="params">(NextFilter nextFilter, IoSession session)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"MyFilter1 sessionCreated"</span>);</span><br><span class="line">        <span class="comment">//屏蔽以下代码后不会再调用MyFilter2的sessionCreated方法</span></span><br><span class="line">        <span class="keyword">super</span>.sessionCreated(nextFilter, session);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyFilter2</span> <span class="keyword">extends</span> <span class="title">IoFilterAdapter</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">sessionCreated</span><span class="params">(NextFilter nextFilter, IoSession session)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"MyFilter2 sessionCreated"</span>);</span><br><span class="line">        <span class="keyword">super</span>.sessionCreated(nextFilter, session);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h2 id="BlacklistFilter"><a href="#BlacklistFilter" class="headerlink" title="BlacklistFilter"></a>BlacklistFilter</h2><p>　　考虑到系统安全性的问题，我们经常需要限制某些客户端的访问，此时就用到了mina为我们提供的黑名单过滤器，核心代码如下：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BlacklistFilter</span> <span class="keyword">extends</span> <span class="title">IoFilterAdapter</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> List&lt;Subnet&gt; blacklist = <span class="keyword">new</span> CopyOnWriteArrayList&lt;Subnet&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setBlacklist</span><span class="params">(InetAddress[] addresses)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (addresses == <span class="keyword">null</span>) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">"addresses"</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        blacklist.clear();</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; addresses.length; i++) &#123;</span><br><span class="line">            InetAddress addr = addresses[i];</span><br><span class="line">            block(addr);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">	</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setSubnetBlacklist</span><span class="params">(Subnet[] subnets)</span> </span>&#123;</span><br><span class="line">        blacklist.clear();</span><br><span class="line">        <span class="keyword">for</span> (Subnet subnet : subnets) &#123;</span><br><span class="line">            block(subnet);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">	</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">block</span><span class="params">(InetAddress address)</span> </span>&#123;</span><br><span class="line">        block(<span class="keyword">new</span> Subnet(address, <span class="number">32</span>));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">block</span><span class="params">(Subnet subnet)</span> </span>&#123;</span><br><span class="line">        blacklist.add(subnet);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">unblock</span><span class="params">(InetAddress address)</span> </span>&#123;</span><br><span class="line">        unblock(<span class="keyword">new</span> Subnet(address, <span class="number">32</span>));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">unblock</span><span class="params">(Subnet subnet)</span> </span>&#123;</span><br><span class="line">        blacklist.remove(subnet);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//sessionOpened、sessionIdle等方法的处理逻辑与sessionCreated一致</span></span><br><span class="line">    <span class="annotation">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">sessionCreated</span><span class="params">(NextFilter nextFilter, IoSession session)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (!isBlocked(session)) &#123;</span><br><span class="line">            nextFilter.sessionCreated(session);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            blockSession(session);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">blockSession</span><span class="params">(IoSession session)</span> </span>&#123;</span><br><span class="line">        LOGGER.warn(<span class="string">"Remote address in the blacklist; closing."</span>);</span><br><span class="line">        session.close(<span class="keyword">true</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">boolean</span> <span class="title">isBlocked</span><span class="params">(IoSession session)</span> </span>&#123;</span><br><span class="line">        SocketAddress remoteAddress = session.getRemoteAddress();</span><br><span class="line">        <span class="keyword">if</span> (remoteAddress <span class="keyword">instanceof</span> InetSocketAddress) &#123;</span><br><span class="line">            InetAddress address = ((InetSocketAddress) remoteAddress).getAddress();</span><br><span class="line">            <span class="keyword">for</span> (Subnet subnet : blacklist) &#123;</span><br><span class="line">                <span class="keyword">if</span> (subnet.inSubnet(address)) &#123;</span><br><span class="line">                    <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　可以看到，在BlacklistFilter过滤器中维护了一个黑名单列表，每次sessionCreated或者messageReceived执行时，都需要检测客户端的ip是否在黑名单中，不在则正常处理，在则关闭连接。至于在sessionCreated、messageReceived等方法中都需要判断，是为了支持动态添加黑名单的能力！</p>
<h2 id="ConnectionThrottleFilter"><a href="#ConnectionThrottleFilter" class="headerlink" title="ConnectionThrottleFilter"></a>ConnectionThrottleFilter</h2><p>　　同样考虑到客户端短时间进行大量连接的问题，防止系统撑爆，通过该过滤器限制客户端的连接频率！<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ConnectionThrottleFilter</span> <span class="keyword">extends</span> <span class="title">IoFilterAdapter</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">long</span> DEFAULT_TIME = <span class="number">1000</span>;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">long</span> allowedInterval;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Map&lt;String, Long&gt; clients;</span><br><span class="line">    <span class="keyword">private</span> Lock lock = <span class="keyword">new</span> ReentrantLock();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="class"><span class="keyword">class</span> <span class="title">ExpiredSessionThread</span> <span class="keyword">extends</span> <span class="title">Thread</span> </span>&#123;</span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                Thread.sleep(allowedInterval);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line">            &#125;</span><br><span class="line">			</span><br><span class="line">            <span class="keyword">long</span> currentTime = System.currentTimeMillis();</span><br><span class="line">            lock.lock();</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                Iterator&lt;String&gt; sessions = clients.keySet().iterator();</span><br><span class="line"></span><br><span class="line">                <span class="keyword">while</span> (sessions.hasNext()) &#123;</span><br><span class="line">                    String session = sessions.next();</span><br><span class="line">                    <span class="keyword">long</span> creationTime = clients.get(session);</span><br><span class="line">                    <span class="keyword">if</span> (creationTime + allowedInterval &lt; currentTime) &#123;</span><br><span class="line">                        clients.remove(session);</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">                lock.unlock();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">	</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">ConnectionThrottleFilter</span><span class="params">(<span class="keyword">long</span> allowedInterval)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.allowedInterval = allowedInterval;</span><br><span class="line">        clients = <span class="keyword">new</span> ConcurrentHashMap&lt;String, Long&gt;();</span><br><span class="line"></span><br><span class="line">        ExpiredSessionThread cleanupThread = <span class="keyword">new</span> ExpiredSessionThread();</span><br><span class="line">        cleanupThread.setDaemon(<span class="keyword">true</span>);</span><br><span class="line">        cleanupThread.start();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setAllowedInterval</span><span class="params">(<span class="keyword">long</span> allowedInterval)</span> </span>&#123;</span><br><span class="line">        lock.lock();</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">this</span>.allowedInterval = allowedInterval;</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            lock.unlock();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">	</span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">boolean</span> <span class="title">isConnectionOk</span><span class="params">(IoSession session)</span> </span>&#123;</span><br><span class="line">        SocketAddress remoteAddress = session.getRemoteAddress();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (remoteAddress <span class="keyword">instanceof</span> InetSocketAddress) &#123;</span><br><span class="line">            InetSocketAddress addr = (InetSocketAddress) remoteAddress;</span><br><span class="line">            <span class="keyword">long</span> now = System.currentTimeMillis();</span><br><span class="line"></span><br><span class="line">            lock.lock();</span><br><span class="line"></span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="keyword">if</span> (clients.containsKey(addr.getAddress().getHostAddress())) &#123;</span><br><span class="line"></span><br><span class="line">                    LOGGER.debug(<span class="string">"This is not a new client"</span>);</span><br><span class="line">                    Long lastConnTime = clients.get(addr.getAddress().getHostAddress());</span><br><span class="line"></span><br><span class="line">                    clients.put(addr.getAddress().getHostAddress(), now);</span><br><span class="line"></span><br><span class="line">                    <span class="comment">// if the interval between now and the last connection is</span></span><br><span class="line">                    <span class="comment">// less than the allowed interval, return false</span></span><br><span class="line">                    <span class="keyword">if</span> (now - lastConnTime &lt; allowedInterval) &#123;</span><br><span class="line">                        LOGGER.warn(<span class="string">"Session connection interval too short"</span>);</span><br><span class="line">                        <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">                    &#125;</span><br><span class="line"></span><br><span class="line">                    <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                clients.put(addr.getAddress().getHostAddress(), now);</span><br><span class="line">            &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">                lock.unlock();</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">sessionCreated</span><span class="params">(NextFilter nextFilter, IoSession session)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (!isConnectionOk(session)) &#123;</span><br><span class="line">            LOGGER.warn(<span class="string">"Connections coming in too fast; closing."</span>);</span><br><span class="line">            session.close(<span class="keyword">true</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        nextFilter.sessionCreated(session);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　每次新客户端连接时，获取其ip和当前时间。先判断Map中（ip=&gt;time）是否存在该客户端的ip，存在则判断上次连接时间与本次连接时间间隔，比预设的小则管理，否则正常流程。不存在则直接方法Map中。</p>
<h2 id="u6570_u636E_u8F6C_u6362"><a href="#u6570_u636E_u8F6C_u6362" class="headerlink" title="数据转换"></a>数据转换</h2><p>　　如果需要自定义过滤器，实现对发送的数据类型进行转换，最好同时实现 filterWrite() 和 messageSent() 方法，如下所示。我们可以参考 WriteRequestFilter 和 AbstractStreamWriteFilter 等的实现。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">filterWrite</span><span class="params">(NextFilter nextFilter, IoSession session, WriteRequest request)</span> </span>&#123;  </span><br><span class="line">    nextFilter.filterWrite(  </span><br><span class="line">        session, <span class="keyword">new</span> DefaultWriteRequest(((String) request.getMessage()).toCharArray(), request.getFuture(), request.getDestination()));  </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">messageSent</span><span class="params">(NextFilter nextFilter, IoSession session, Object message)</span> </span>&#123;  </span><br><span class="line">    nextFilter.messageSent(session, <span class="keyword">new</span> String((<span class="keyword">char</span>[]) message));  </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//下面的实现方法更加高效</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">filterWrite</span><span class="params">(NextFilter nextFilter, IoSession session, WriteRequest request)</span> </span>&#123;  </span><br><span class="line">    String m = (String) request.getMessage();  </span><br><span class="line">    ByteBuffer newBuffer = <span class="keyword">new</span> MyByteBuffer(m, ByteBuffer.wrap(m.getBytes());  </span><br><span class="line">  </span><br><span class="line">    nextFilter.filterWrite(  </span><br><span class="line">            session, <span class="keyword">new</span> WriteRequest(newBuffer, request.getFuture(), request.getDestination()));  </span><br><span class="line">&#125;  </span><br><span class="line">  </span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">messageSent</span><span class="params">(NextFilter nextFilter, IoSession session, Object message)</span> </span>&#123;  </span><br><span class="line">    <span class="keyword">if</span> (message <span class="keyword">instanceof</span> MyByteBuffer) &#123;  </span><br><span class="line">        nextFilter.messageSent(session, ((MyByteBuffer) message).originalValue);  </span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;  </span><br><span class="line">        nextFilter.messageSent(session, message);  </span><br><span class="line">    &#125;  </span><br><span class="line">&#125;  </span><br><span class="line">  </span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">MyByteBuffer</span> <span class="keyword">extends</span> <span class="title">ByteBufferProxy</span> </span>&#123;  </span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Object originalValue;  </span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="title">MyByteBuffer</span><span class="params">(Object originalValue, ByteBuffer encodedValue)</span> </span>&#123;  </span><br><span class="line">        <span class="keyword">super</span>(encodedValue);  </span><br><span class="line">        <span class="keyword">this</span>.originalValue = originalValue;  </span><br><span class="line">    &#125;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h2 id="ExecutorFilter"><a href="#ExecutorFilter" class="headerlink" title="ExecutorFilter"></a>ExecutorFilter</h2><p>　　首先，一个客户端连接只使用一个线程NioProcessor，如果handler的业务比较耗时，会导致NioProcessor线程堵塞。一个NioProcessor线程会处理多个客户端的连接，这样某个handler耗时处理就会影响其他客户端的处理。此时需要采用独立的线程处理Handler，在 FilterChain 的最后增加一个ExecutorFitler即可！<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="comment">//客户端在sessionOpened方法中发送五条消息</span></span><br><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">sessionOpened</span><span class="params">(IoSession session)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">    session.write(<span class="string">"hello1"</span>);</span><br><span class="line">    session.write(<span class="string">"hello2"</span>);</span><br><span class="line">    session.write(<span class="string">"hello3"</span>);</span><br><span class="line">    session.write(<span class="string">"hello4"</span>);</span><br><span class="line">    session.write(<span class="string">"hello5"</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//服务端增加过滤器</span></span><br><span class="line">acceptor.getFilterChain().addLast(<span class="string">"threadPool"</span>, <span class="keyword">new</span> ExecutorFilter(Executors.newCachedThreadPool()));</span><br><span class="line"></span><br><span class="line"><span class="comment">//服务端的messageReceived方法修改后如下</span></span><br><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">messageReceived</span><span class="params">( IoSession session, Object message )</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line"></span><br><span class="line">	Thread.sleep(<span class="number">2000</span>);</span><br><span class="line">	<span class="comment">//不添加ExecutorFilter时输出：Handler处理时线程：NioProcessor-2</span></span><br><span class="line">	<span class="comment">// 每隔2秒输出一次消息</span></span><br><span class="line"></span><br><span class="line">	<span class="comment">//添加ExecutorFilter时输出：Handler处理时线程：pool-3-thread-1、Handler处理时线程：pool-3-thread-3等</span></span><br><span class="line">	<span class="comment">//五条消息几乎同时输出</span></span><br><span class="line">	System.out.println(<span class="string">"Handler处理时线程："</span> + Thread.currentThread().getName());</span><br><span class="line">	</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　在处理流程中加入线程池ExecutorFilter过滤器，可以较好的提高服务器的吞吐量，但也带来了新的问题：<strong>同一个IoSession的多个IO请求可能被ExecutorFilter并行的处理</strong>，这对于一些对请求处理顺序有要求的程序来说是不希望看到的。比如：数据库服务器处理同一个会话里的prepare，execute，commit请求希望是能按顺序逐一执行的。<br>　　Mina里默认的实现是有保证同一个IoSession中IO请求的顺序的。具体的实现是，ExecutorFilter默认采用了Mina提供的OrderedThreadPoolExecutor作为内置线程池。后者并不会立即执行加入进来的Runnable对象，而是会先从Runnable对象里获取关联的IoSession(这里有个down cast成IoEvent的操作)，并将Runnable对象加入到session的任务列表中。OrderedThreadPoolExecutor会按session里任务列表的顺序来处理请求，从而保证了请求的执行顺序。<br>　　对于没有顺序要请求的情况，可以为ExecutorFilter指定一个Executor来替换掉默认的OrderedThreadPoolExecutor，让同一个session的多个请求能被并行地处理，来进一步提高吞吐量。</p>
<h2 id="u53C2_u8003_u94FE_u63A5"><a href="#u53C2_u8003_u94FE_u63A5" class="headerlink" title="参考链接"></a>参考链接</h2><p><a href="http://mina.apache.org/mina-project/quick-start-guide.html" target="_blank" rel="external">http://mina.apache.org/mina-project/quick-start-guide.html</a><br><a href="http://blog.csdn.net/yoara/article/details/37597141" target="_blank" rel="external">http://blog.csdn.net/yoara/article/details/37597141</a></p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2016/01/18/nio/17.Mina系列三之IoFilter/" data-id="cijzzpv7c005m1cfsjnkss18g" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/mina/">mina</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/nio/">nio</a></li></ul>

    </footer>
  </div>
  
    
<nav id="article-nav">
  
    <a href="/2016/01/19/nio/18.Mina系列四之IoService/" id="article-nav-newer" class="article-nav-link-wrap">
      <strong class="article-nav-caption">Newer</strong>
      <div class="article-nav-title">
        
          Mina系列四之IoService
        
      </div>
    </a>
  
  
    <a href="/2016/01/18/nio/16.Mina系列二之示例/" id="article-nav-older" class="article-nav-link-wrap">
      <strong class="article-nav-caption">Older</strong>
      <div class="article-nav-title">Mina系列二之示例</div>
    </a>
  
</nav>

  
</article>

</section>
        
          <aside id="sidebar">
  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Categories</h3>
    <div class="widget">
      <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/cache/">cache</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/database/">database</a><span class="category-list-count">13</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/docker/">docker</a><span class="category-list-count">6</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/gis/">gis</a><span class="category-list-count">4</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/git/">git</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/go/">go</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/gradle/">gradle</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/groovy/">groovy</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/hadoop/">hadoop</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/java/">java</a><span class="category-list-count">18</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/linux/">linux</a><span class="category-list-count">4</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/log/">log</a><span class="category-list-count">11</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/mongodb/">mongodb</a><span class="category-list-count">14</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/mq/">mq</a><span class="category-list-count">6</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/mybatis/">mybatis</a><span class="category-list-count">9</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/netty/">netty</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/nginx/">nginx</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/nio/">nio</a><span class="category-list-count">19</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/nodejs/">nodejs</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/redis/">redis</a><span class="category-list-count">6</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/rpc/">rpc</a><span class="category-list-count">14</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/spring/">spring</a><span class="category-list-count">5</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/tomcat/">tomcat</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/zookeeper/">zookeeper</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/杂项/">杂项</a><span class="category-list-count">2</span></li></ul>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Tags</h3>
    <div class="widget">
      <ul class="tag-list"><li class="tag-list-item"><a class="tag-list-link" href="/tags/aop/">aop</a><span class="tag-list-count">8</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/aspectj/">aspectj</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/cache/">cache</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/classloader/">classloader</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/common-loggings/">common-loggings</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/commonjs/">commonjs</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/database/">database</a><span class="tag-list-count">10</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/docker/">docker</a><span class="tag-list-count">6</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/dubbo/">dubbo</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/fastdfs/">fastdfs</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/gclib/">gclib</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/geohash/">geohash</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/gis/">gis</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/git/">git</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/go/">go</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/gradle/">gradle</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/groovy/">groovy</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/hadoop/">hadoop</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/hessisan/">hessisan</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/java/">java</a><span class="tag-list-count">48</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/javassist/">javassist</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/kafka/">kafka</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/linux/">linux</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/log/">log</a><span class="tag-list-count">11</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/log4j/">log4j</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/logback/">logback</a><span class="tag-list-count">5</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/map/">map</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/memecached/">memecached</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mina/">mina</a><span class="tag-list-count">5</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mongodb/">mongodb</a><span class="tag-list-count">14</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mq/">mq</a><span class="tag-list-count">6</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mqtt/">mqtt</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mybatis/">mybatis</a><span class="tag-list-count">9</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/netty/">netty</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/nginx/">nginx</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/nio/">nio</a><span class="tag-list-count">5</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/nodejs/">nodejs</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/postgresql/">postgresql</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/protobuf/">protobuf</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/proxy/">proxy</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/push/">push</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/rabbitmq/">rabbitmq</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/redis/">redis</a><span class="tag-list-count">6</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/rpc/">rpc</a><span class="tag-list-count">14</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/sitemesh/">sitemesh</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/sld/">sld</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/slf4j/">slf4j</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/socket/">socket</a><span class="tag-list-count">7</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/spatialite-for-android/">spatialite for android</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/spi/">spi</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/spring/">spring</a><span class="tag-list-count">13</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/tomcat/">tomcat</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/transaction/">transaction</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/web/">web</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/xSocket/">xSocket</a><span class="tag-list-count">7</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/zbus/">zbus</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/zookeeper/">zookeeper</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/数据结构/">数据结构</a><span class="tag-list-count">2</span></li></ul>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Tag Cloud</h3>
    <div class="widget tagcloud">
      <a href="/tags/aop/" style="font-size: 15.38px;">aop</a> <a href="/tags/aspectj/" style="font-size: 11.54px;">aspectj</a> <a href="/tags/cache/" style="font-size: 11.54px;">cache</a> <a href="/tags/classloader/" style="font-size: 10px;">classloader</a> <a href="/tags/common-loggings/" style="font-size: 10px;">common-loggings</a> <a href="/tags/commonjs/" style="font-size: 12.31px;">commonjs</a> <a href="/tags/database/" style="font-size: 16.92px;">database</a> <a href="/tags/docker/" style="font-size: 13.85px;">docker</a> <a href="/tags/dubbo/" style="font-size: 10px;">dubbo</a> <a href="/tags/fastdfs/" style="font-size: 10px;">fastdfs</a> <a href="/tags/gclib/" style="font-size: 10.77px;">gclib</a> <a href="/tags/geohash/" style="font-size: 10px;">geohash</a> <a href="/tags/gis/" style="font-size: 10px;">gis</a> <a href="/tags/git/" style="font-size: 10.77px;">git</a> <a href="/tags/go/" style="font-size: 10px;">go</a> <a href="/tags/gradle/" style="font-size: 10px;">gradle</a> <a href="/tags/groovy/" style="font-size: 10px;">groovy</a> <a href="/tags/hadoop/" style="font-size: 10px;">hadoop</a> <a href="/tags/hessisan/" style="font-size: 11.54px;">hessisan</a> <a href="/tags/java/" style="font-size: 20px;">java</a> <a href="/tags/javassist/" style="font-size: 10px;">javassist</a> <a href="/tags/kafka/" style="font-size: 11.54px;">kafka</a> <a href="/tags/linux/" style="font-size: 12.31px;">linux</a> <a href="/tags/log/" style="font-size: 17.69px;">log</a> <a href="/tags/log4j/" style="font-size: 12.31px;">log4j</a> <a href="/tags/logback/" style="font-size: 13.08px;">logback</a> <a href="/tags/map/" style="font-size: 10px;">map</a> <a href="/tags/memecached/" style="font-size: 10.77px;">memecached</a> <a href="/tags/mina/" style="font-size: 13.08px;">mina</a> <a href="/tags/mongodb/" style="font-size: 19.23px;">mongodb</a> <a href="/tags/mq/" style="font-size: 13.85px;">mq</a> <a href="/tags/mqtt/" style="font-size: 10.77px;">mqtt</a> <a href="/tags/mybatis/" style="font-size: 16.15px;">mybatis</a> <a href="/tags/netty/" style="font-size: 10px;">netty</a> <a href="/tags/nginx/" style="font-size: 11.54px;">nginx</a> <a href="/tags/nio/" style="font-size: 13.08px;">nio</a> <a href="/tags/nodejs/" style="font-size: 10px;">nodejs</a> <a href="/tags/postgresql/" style="font-size: 10.77px;">postgresql</a> <a href="/tags/protobuf/" style="font-size: 10px;">protobuf</a> <a href="/tags/proxy/" style="font-size: 10px;">proxy</a> <a href="/tags/push/" style="font-size: 10px;">push</a> <a href="/tags/rabbitmq/" style="font-size: 11.54px;">rabbitmq</a> <a href="/tags/redis/" style="font-size: 13.85px;">redis</a> <a href="/tags/rpc/" style="font-size: 19.23px;">rpc</a> <a href="/tags/sitemesh/" style="font-size: 10px;">sitemesh</a> <a href="/tags/sld/" style="font-size: 10px;">sld</a> <a href="/tags/slf4j/" style="font-size: 10px;">slf4j</a> <a href="/tags/socket/" style="font-size: 14.62px;">socket</a> <a href="/tags/spatialite-for-android/" style="font-size: 10px;">spatialite for android</a> <a href="/tags/spi/" style="font-size: 10px;">spi</a> <a href="/tags/spring/" style="font-size: 18.46px;">spring</a> <a href="/tags/tomcat/" style="font-size: 10.77px;">tomcat</a> <a href="/tags/transaction/" style="font-size: 10px;">transaction</a> <a href="/tags/web/" style="font-size: 10px;">web</a> <a href="/tags/xSocket/" style="font-size: 14.62px;">xSocket</a> <a href="/tags/zbus/" style="font-size: 10px;">zbus</a> <a href="/tags/zookeeper/" style="font-size: 10.77px;">zookeeper</a> <a href="/tags/数据结构/" style="font-size: 10.77px;">数据结构</a>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Archives</h3>
    <div class="widget">
      <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2016/01/">January 2016</a><span class="archive-list-count">67</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/12/">December 2015</a><span class="archive-list-count">81</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/11/">November 2015</a><span class="archive-list-count">2</span></li></ul>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Recents</h3>
    <div class="widget">
      <ul>
        
          <li>
            <a href="/2016/01/30/资料/">(no title)</a>
          </li>
        
          <li>
            <a href="/2016/01/30/java/13.Classloader系列一/">ClassLoader系列一</a>
          </li>
        
          <li>
            <a href="/2016/01/29/hadoop/1.hadoop系列之源码编译/">hadoop系列一之源码编译</a>
          </li>
        
          <li>
            <a href="/2016/01/29/go/1.GO系列之入门/">Go系列一之入门</a>
          </li>
        
          <li>
            <a href="/2016/01/28/tomcat/2.tomcat性能优化/">tomcat性能优化</a>
          </li>
        
      </ul>
    </div>
  </div>

  
</aside>
        
      </div>
      <footer id="footer">
  
  <div class="outer">
    <div id="footer-info" class="inner">
      &copy; 2016 John Doe<br>
      Powered by <a href="http://hexo.io/" target="_blank">Hexo</a>
    </div>
  </div>
</footer>
    </div>
    <nav id="mobile-nav">
  
    <a href="/" class="mobile-nav-link">Home</a>
  
    <a href="/archives" class="mobile-nav-link">Archives</a>
  
</nav>
    


<script src="http://libs.baidu.com/jquery/2.0.3/jquery.min.js"></script>


  <link rel="stylesheet" href="/fancybox/jquery.fancybox.css" type="text/css">
  <script src="/fancybox/jquery.fancybox.pack.js" type="text/javascript"></script>


<script src="/js/script.js" type="text/javascript"></script>

  </div>
</body>
</html>